package com.zyb.insurance.policy.infrastructure;

import com.zyb.insurance.common.ElasticsearchClient;
import com.zyb.insurance.policy.entity.InsurancePolicy;
import com.zyb.insurance.policy.entity.InsurancePolicyAttendant;
import com.zyb.insurance.policy.entity.SearchParameters;
import com.zyb.insurance.common.ElasticsearchClient;
import com.zyb.insurance.policy.entity.SearchParameters;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class ElasticsearchManager {

    public void createInsurancePolicyIndexIfNotExits() {
        try {
            ElasticsearchClient elasticsearchClient = ElasticsearchClient.getInstance();
            RestHighLevelClient restHighLevelClient = elasticsearchClient.getRestHighLevelClient();

            GetIndexRequest getIndexRequest = new GetIndexRequest("insurance_policy_index");
            boolean exists = restHighLevelClient.indices().exists(
                    getIndexRequest, RequestOptions.DEFAULT);

            if(exists) {
                System.out.println("保单数据索引已经存在，不能重复创建......");
                return;
            }
            System.out.println("保单数据索引不存在，即将创建......");

            CreateIndexRequest createIndexRequest = new CreateIndexRequest("insurance_policy_index");

            createIndexRequest.settings(Settings.builder()
                    .put("index.number_of_shards", 10)
                    .put("index.number_of_replicas", 2)
            );

            // 把每个字段的配置，都放到一个properties map里去
            Map<String, Object> properties = new HashMap<String, Object>();
            properties.put("insuranceCompany", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("insuranceProduct", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("issueInsurancePolicyOrganization", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("issueInsurancePolicyStaff", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("insurancePolicyYearNumber", new HashMap<String, Object>(){ { put("type", "integer"); } });
            properties.put("payPeriod", new HashMap<String, Object>(){ { put("type", "integer"); } });
            properties.put("contractCode", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("proposalFormCode", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("policyHolderName", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("policyHolderPhoneNumber", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("policyHolderCredentialsNumber", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("insurant", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("insuranceCompanyType", new HashMap<String, Object>(){ { put("type", "integer"); } });
            properties.put("insuranceProductType", new HashMap<String, Object>(){ { put("type", "integer"); } });
            properties.put("insurancePolicyAttendants", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("operator", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("tags", new HashMap<String, Object>(){ { put("type", "keyword"); } });
            properties.put("deliveryDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("insureDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("firstExaminationDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("acceptInsuranceDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("beginValidDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("receiptSignDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("receiptInputDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("noticeSignDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("hesitatePeriodExpiryDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("secondExaminationDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("returnVisitDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("verifyAccountDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("giveOutBrokerageDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("postponeDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("rejectDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("cancelDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("refundDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("expiryDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("expiredDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("resumeDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("payDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("settleBrokerageDate", new HashMap<String, Object>(){ { put("type", "date"); } });
            properties.put("reportDate", new HashMap<String, Object>(){ { put("type", "date"); } });

            // properties map放到mapping map里去
            Map<String, Object> mapping = new HashMap<String, Object>();
            mapping.put("properties", properties);

            // 最后完成mapping的设置
            createIndexRequest.mapping(mapping);

            // 创建索引
            CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(
                    createIndexRequest, RequestOptions.DEFAULT);
            System.out.println("创建保单数据索引结果：" + createIndexResponse.isAcknowledged());
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public void buildInsurancePolicyIndex(InsurancePolicy insurancePolicy) throws Exception {
        ElasticsearchClient elasticsearchClient = ElasticsearchClient.getInstance();
        RestHighLevelClient restHighLevelClient = elasticsearchClient.getRestHighLevelClient();

        Map<String, Object> jsonMap = new HashMap<String, Object>();
        jsonMap.put("insuranceCompany", insurancePolicy.getInsuranceContract().getInsuranceCompany().getChineseName());
        jsonMap.put("insuranceProduct", insurancePolicy.getInsuranceContract().getInsuranceProduct().getName());
        jsonMap.put("issueInsurancePolicyOrganization", insurancePolicy.getInsuranceContract().getIssueInsurancePolicyOrganization().name());
        jsonMap.put("issueInsurancePolicyStaff", insurancePolicy.getInsuranceContract().getIssueInsurancePolicyStaff().getChineseName());
        jsonMap.put("insurancePolicyYearNumber", insurancePolicy.getInsuranceContract().getInsurancePolicyYearNumber());
        jsonMap.put("payPeriod", insurancePolicy.getInsuranceContract().getPayPeriod());
        jsonMap.put("contractCode", insurancePolicy.getInsuranceContract().getContractCode());
        jsonMap.put("proposalFormCode", insurancePolicy.getInsuranceContract().getProposalFormCode());
        jsonMap.put("policyHolderName", insurancePolicy.getPolicyHolder().getName());
        jsonMap.put("policyHolderPhoneNumber", insurancePolicy.getPolicyHolder().getPhoneNumber());
        jsonMap.put("policyHolderCredentialsNumber", insurancePolicy.getPolicyHolder().getCredentialsNumber());
        jsonMap.put("insurant", insurancePolicy.getPolicyHolder().getName());
        jsonMap.put("insuranceCompanyType", insurancePolicy.getInsuranceContract().getInsuranceCompany().getInsuranceCompanyType());
        jsonMap.put("insuranceProductType", insurancePolicy.getInsuranceContract().getInsuranceProduct().getInsuranceProductType());


        List<InsurancePolicyAttendant> insurancePolicyAttendants = insurancePolicy.getInsuranceContract().getInsurancePolicyAttendants();
        List<String> insurancePolicyAttendantNames = new ArrayList<String>();
        for(InsurancePolicyAttendant insurancePolicyAttendant : insurancePolicyAttendants) {
            insurancePolicyAttendantNames.add(insurancePolicyAttendant.getInsurancePolicyAttendant().getChineseName());
        }
        jsonMap.put("insurancePolicyAttendants", insurancePolicyAttendantNames);

        jsonMap.put("operator", insurancePolicy.getInsuranceContract().getOperator());
        jsonMap.put("tags", insurancePolicy.getInsuranceContract().getTags());
        jsonMap.put("deliveryDate", insurancePolicy.getInsurancePolicyContractStatus().getDeliveryDate());
        jsonMap.put("insureDate", insurancePolicy.getInsurancePolicyContractStatus().getInsureDate());
        jsonMap.put("firstExaminationDate", insurancePolicy.getInsurancePolicyContractStatus().getFirstExaminationDate());
        jsonMap.put("acceptInsuranceDate", insurancePolicy.getInsurancePlan().getAcceptInsuranceDate());
        jsonMap.put("beginValidDate", insurancePolicy.getInsurancePlan().getBeginValidDate());
        jsonMap.put("receiptSignDate", insurancePolicy.getInsurancePolicyContractStatus().getReceiptSignDate());
        jsonMap.put("receiptInputDate", insurancePolicy.getInsurancePolicyContractStatus().getReceiptInputDate());
        jsonMap.put("noticeSignDate", insurancePolicy.getInsurancePolicyContractStatus().getNoticeSignDate());
        jsonMap.put("hesitatePeriodExpiryDate", insurancePolicy.getInsurancePolicyContractStatus().getHesitatePeriodExpiryDate());
        jsonMap.put("secondExaminationDate", insurancePolicy.getInsurancePolicyContractStatus().getSecondExaminationDate());
        jsonMap.put("returnVisitDate", insurancePolicy.getInsurancePolicyContractStatus().getReturnVisitDate());
        jsonMap.put("verifyAccountDate", insurancePolicy.getInsurancePlan().getVerifyAccountDate());
        jsonMap.put("giveOutBrokerageDate", insurancePolicy.getInsurancePlan().getGiveOutBrokerageDate());
        jsonMap.put("postponeDate", insurancePolicy.getInsurancePolicyContractStatus().getPostponeDate());
        jsonMap.put("rejectDate", insurancePolicy.getInsurancePolicyContractStatus().getRejectDate());
        jsonMap.put("cancelDate", insurancePolicy.getInsurancePolicyContractStatus().getCancelDate());
        jsonMap.put("refundDate", insurancePolicy.getInsurancePolicyContractStatus().getRefundDate());
        jsonMap.put("expiryDate", insurancePolicy.getInsurancePolicyContractStatus().getExpiryDate());
        jsonMap.put("expiredDate", insurancePolicy.getInsurancePolicyContractStatus().getExpiredDate());
        jsonMap.put("resumeDate", insurancePolicy.getInsurancePolicyContractStatus().getResumeDate());
        jsonMap.put("payDate", insurancePolicy.getInsurancePlan().getPayDate());
        jsonMap.put("settleBrokerageDate", insurancePolicy.getInsurancePlan().getSettleBrokerageDate());
        jsonMap.put("reportDate", insurancePolicy.getInsurancePlan().getReportDate());

        IndexRequest indexRequest = new IndexRequest(
                "insurance_policy_index", "default", insurancePolicy.getInsurancePolicyId())
                .source(jsonMap);

        IndexResponse indexResponse = restHighLevelClient.index(
                indexRequest, RequestOptions.DEFAULT);
        System.out.println("构建保单索引结果：" + indexResponse.getResult().name());
    }

    public void search(SearchParameters searchParameters) throws Exception{
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        if(searchParameters.getInsuranceCompany() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery(
                    "insuranceCompany", searchParameters.getInsuranceCompany()));
        }
        if(searchParameters.getInsuranceProduct() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery(
                    "insuranceProduct", searchParameters.getInsuranceProduct()));
        }
        if(searchParameters.getIssueInsurancePolicyOrganization() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery(
                    "issueInsurancePolicyOrganization", searchParameters.getIssueInsurancePolicyOrganization()));
        }
        if(searchParameters.getIssueInsurancePolicyStaff() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery(
                    "issueInsurancePolicyStaff", searchParameters.getIssueInsurancePolicyStaff()));
        }
        if(searchParameters.getStartPayPeriod() != null && searchParameters.getEndPayPeriod() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("payPeriod")
                    .from(searchParameters.getStartPayPeriod()).to(searchParameters.getEndPayPeriod()));
        }
        if(searchParameters.getContractCodeOrProposalFormCode() != null) {
            boolQueryBuilder.should(QueryBuilders.termQuery(
                    "contractCode", searchParameters.getContractCodeOrProposalFormCode()));
            boolQueryBuilder.should(QueryBuilders.termQuery(
                    "proposalFormCode", searchParameters.getContractCodeOrProposalFormCode()));
        }
        if(searchParameters.getPolicyHolder() != null) {
            boolQueryBuilder.should(QueryBuilders.termQuery(
                    "policyHolderName", searchParameters.getPolicyHolder()));
            boolQueryBuilder.should(QueryBuilders.termQuery(
                    "policyHolderPhoneNumber", searchParameters.getPolicyHolder()));
            boolQueryBuilder.should(QueryBuilders.termQuery(
                    "policyHolderCredentialsNumber", searchParameters.getPolicyHolder()));
        }
        if(searchParameters.getInsurant() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery(
                    "insurant", searchParameters.getInsurant()));
        }
        if(searchParameters.getInsuranceCompanyType() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery(
                    "insuranceCompanyType", searchParameters.getInsuranceCompanyType()));
        }
        if(searchParameters.getInsuranceProductType() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery(
                    "insuranceProductType", searchParameters.getInsuranceProductType()));
        }
        if(searchParameters.getInsurancePolicyAttendant() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery(
                    "insurancePolicyAttendants", searchParameters.getInsurancePolicyAttendant()));
        }
        if(searchParameters.getOperator() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery(
                    "operator", searchParameters.getOperator()));
        }
        if(searchParameters.getTags() != null) {
            for(String tag : searchParameters.getTags()) {
                boolQueryBuilder.should(QueryBuilders.termQuery("tags", tag));
            }
        }
        if(searchParameters.getStartDeliveryDate() != null &&
                searchParameters.getEndDeliveryDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("deliveryDate")
                    .from(searchParameters.getStartDeliveryDate()).to(searchParameters.getEndDeliveryDate()));
        }
        if(searchParameters.getStartInsureDate() != null &&
                searchParameters.getEndInsureDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("insureDate")
                    .from(searchParameters.getStartInsureDate()).to(searchParameters.getEndFirstExaminationDate()));
        }
        if(searchParameters.getStartFirstExaminationDate() != null &&
                searchParameters.getEndFirstExaminationDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("firstExaminationDate")
                    .from(searchParameters.getStartFirstExaminationDate()).to(searchParameters.getEndInsureDate()));
        }
        if(searchParameters.getStartAcceptInsuranceDate() != null &&
                searchParameters.getEndAcceptInsuranceDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("acceptInsuranceDate")
                    .from(searchParameters.getStartAcceptInsuranceDate()).to(searchParameters.getEndAcceptInsuranceDate()));
        }
        if(searchParameters.getStartBeginValidDate() != null &&
                searchParameters.getEndBeginValidDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("beginValidDate")
                    .from(searchParameters.getStartBeginValidDate()).to(searchParameters.getEndBeginValidDate()));
        }
        if(searchParameters.getStartReceiptSignDate() != null &&
                searchParameters.getEndReceiptSignDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("receiptSignDate")
                    .from(searchParameters.getStartReceiptSignDate()).to(searchParameters.getEndReceiptSignDate()));
        }
        if(searchParameters.getStartReceiptInputDate() != null &&
                searchParameters.getEndReceiptInputDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("receiptInputDate")
                    .from(searchParameters.getStartReceiptInputDate()).to(searchParameters.getEndReceiptInputDate()));
        }
        if(searchParameters.getStartNoticeSignDate() != null &&
                searchParameters.getEndNoticeSignDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("noticeSignDate")
                    .from(searchParameters.getStartNoticeSignDate()).to(searchParameters.getEndNoticeSignDate()));
        }
        if(searchParameters.getStartHesitatePeriodExpiryDate() != null &&
                searchParameters.getEndHesitatePeriodExpiryDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("hesitatePeriodExpiryDate")
                    .from(searchParameters.getStartHesitatePeriodExpiryDate()).to(searchParameters.getEndHesitatePeriodExpiryDate()));
        }
        if(searchParameters.getStartSecondExaminationDate() != null &&
                searchParameters.getEndSecondExaminationDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("secondExaminationDate")
                    .from(searchParameters.getStartSecondExaminationDate()).to(searchParameters.getEndSecondExaminationDate()));
        }
        if(searchParameters.getStartReturnVisitDate() != null &&
                searchParameters.getEndReturnVisitDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("returnVisitDate")
                    .from(searchParameters.getStartReturnVisitDate()).to(searchParameters.getEndReturnVisitDate()));
        }
        if(searchParameters.getStartVerifyAccountDate() != null &&
                searchParameters.getEndVerifyAccountDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("verifyAccountDate")
                    .from(searchParameters.getStartVerifyAccountDate()).to(searchParameters.getEndVerifyAccountDate()));
        }
        if(searchParameters.getStartGiveOutBrokerageDate() != null &&
                searchParameters.getEndGiveOutBrokerageDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("giveOutBrokerageDate")
                    .from(searchParameters.getStartGiveOutBrokerageDate()).to(searchParameters.getEndGiveOutBrokerageDate()));
        }
        if(searchParameters.getStartPostponeDate() != null &&
                searchParameters.getEndPostponeDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("postponeDate")
                    .from(searchParameters.getStartPostponeDate()).to(searchParameters.getEndPostponeDate()));
        }
        if(searchParameters.getStartRejectDate() != null &&
                searchParameters.getEndRejectDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("rejectDate")
                    .from(searchParameters.getStartRejectDate()).to(searchParameters.getEndRejectDate()));
        }
        if(searchParameters.getStartCancelDate() != null &&
                searchParameters.getEndCancelDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("cancelDate")
                    .from(searchParameters.getStartCancelDate()).to(searchParameters.getEndCancelDate()));
        }
        if(searchParameters.getStartRefundDate() != null &&
                searchParameters.getEndRefundDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("refundDate")
                    .from(searchParameters.getStartRefundDate()).to(searchParameters.getEndRefundDate()));
        }
        if(searchParameters.getStartExpiryDate() != null &&
                searchParameters.getEndExpiryDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("expiryDate")
                    .from(searchParameters.getStartExpiryDate()).to(searchParameters.getEndExpiryDate()));
        }
        if(searchParameters.getStartExpiredDate() != null &&
                searchParameters.getEndExpiredDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("expiredDate")
                    .from(searchParameters.getStartExpiredDate()).to(searchParameters.getEndExpiredDate()));
        }
        if(searchParameters.getStartResumeDate() != null &&
                searchParameters.getEndResumeDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("resumeDate")
                    .from(searchParameters.getStartResumeDate()).to(searchParameters.getEndResumeDate()));
        }
        if(searchParameters.getStartPayDate() != null &&
                searchParameters.getEndPayDate() != null) {
            boolQueryBuilder.must(QueryBuilders.rangeQuery("payDate")
                    .from(searchParameters.getStartPayDate()).to(searchParameters.getEndPayDate()));
        }
        if(searchParameters.getSettleBrokerageDate() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery("settleBrokerageDate",
                    searchParameters.getSettleBrokerageDate()));
        }
        if(searchParameters.getReportDate() != null) {
            boolQueryBuilder.must(QueryBuilders.termQuery("reportDate",
                    searchParameters.getReportDate()));
        }
        boolQueryBuilder.minimumShouldMatch(3);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder);
        searchSourceBuilder.sort(new FieldSortBuilder("beginValidDate").order(SortOrder.DESC));
        searchSourceBuilder.from(searchParameters.getFrom());
        searchSourceBuilder.size(searchParameters.getSize());

        SearchRequest searchRequest = new SearchRequest("insurance_policy_index");
        searchRequest.source(searchSourceBuilder);

        ElasticsearchClient elasticsearchClient = ElasticsearchClient.getInstance();
        RestHighLevelClient restHighLevelClient = elasticsearchClient.getRestHighLevelClient();
        SearchResponse searchResponse = restHighLevelClient.search(
                searchRequest, RequestOptions.DEFAULT);

        for(SearchHit searchHit : searchResponse.getHits().getHits()) {
            System.out.println(searchHit.getSourceAsMap());
        }
    }

}
